using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Net;
using System.Threading;

namespace muduoDotNet
{
    /// <summary>
    /// 连接池管理器
    /// 用于管理TCP连接的复用，提高高并发场景下的性能
    /// </summary>
    public class ConnectionPool : IDisposable
    {
        private readonly ConcurrentQueue<TcpConnection> _availableConnections;
        private readonly ConcurrentDictionary<string, TcpConnection> _activeConnections;
        private readonly IPEndPoint _remoteEndPoint;
        private readonly EventLoop _eventLoop;
        private readonly int _maxPoolSize;
        private readonly int _minPoolSize;
        private readonly object _poolLock = new object();
        private bool _disposed = false;
        
        /// <summary>
        /// 连接池事件回调
        /// </summary>
        public Action<TcpConnection> ConnectionCreatedCallback { get; set; }
        public Action<TcpConnection> ConnectionDestroyedCallback { get; set; }
        public Action<TcpConnection> ConnectionAcquiredCallback { get; set; }
        public Action<TcpConnection> ConnectionReleasedCallback { get; set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="eventLoop">事件循环</param>
        /// <param name="remoteEndPoint">远程端点</param>
        /// <param name="minPoolSize">最小连接池大小</param>
        /// <param name="maxPoolSize">最大连接池大小</param>
        public ConnectionPool(EventLoop eventLoop, IPEndPoint remoteEndPoint, int minPoolSize = 5, int maxPoolSize = 100)
        {
            _eventLoop = eventLoop ?? throw new ArgumentNullException(nameof(eventLoop));
            _remoteEndPoint = remoteEndPoint ?? throw new ArgumentNullException(nameof(remoteEndPoint));
            _minPoolSize = Math.Max(0, minPoolSize);
            _maxPoolSize = Math.Max(_minPoolSize, maxPoolSize);
            
            _availableConnections = new ConcurrentQueue<TcpConnection>();
            _activeConnections = new ConcurrentDictionary<string, TcpConnection>();
            
            // 初始化最小连接数
            InitializeMinConnections();
        }

        /// <summary>
        /// 初始化最小连接数
        /// </summary>
        private void InitializeMinConnections()
        {
            for (int i = 0; i < _minPoolSize; i++)
            {
                try
                {
                    var connection = CreateConnection();
                    if (connection != null)
                    {
                        _availableConnections.Enqueue(connection);
                        ConnectionCreatedCallback?.Invoke(connection);
                    }
                }
                catch (Exception ex)
                {
                    Logger.Error($"Failed to initialize connection in pool: {ex.Message}", ex);
                }
            }
        }

        /// <summary>
        /// 创建新连接
        /// </summary>
        /// <returns>TCP连接</returns>
        private TcpConnection CreateConnection()
        {
            try
            {
                var socket = new System.Net.Sockets.Socket(
                    _remoteEndPoint.AddressFamily,
                    System.Net.Sockets.SocketType.Stream,
                    System.Net.Sockets.ProtocolType.Tcp);
                
                // 设置Socket选项
                socket.SetSocketOption(System.Net.Sockets.SocketOptionLevel.Socket, 
                                     System.Net.Sockets.SocketOptionName.ReuseAddress, true);
                socket.SetSocketOption(System.Net.Sockets.SocketOptionLevel.Socket, 
                                     System.Net.Sockets.SocketOptionName.KeepAlive, true);
                
                var connectionName = $"pooled_connection_{Guid.NewGuid():N}";
                var connection = new TcpConnection(_eventLoop, connectionName, socket);
                
                // 设置连接回调
                connection.ConnectionCallback = OnConnectionStateChanged;
                connection.CloseCallback = OnConnectionClosed;
                
                return connection;
            }
            catch (Exception ex)
            {
                Logger.Error($"Failed to create connection: {ex.Message}", ex);
                return null;
            }
        }

        /// <summary>
        /// 获取连接
        /// </summary>
        /// <returns>TCP连接</returns>
        public TcpConnection AcquireConnection()
        {
            if (_disposed)
                throw new ObjectDisposedException(nameof(ConnectionPool));

            TcpConnection connection = null;
            
            // 首先尝试从可用连接队列中获取
            if (_availableConnections.TryDequeue(out connection))
            {
                // 检查连接是否仍然有效
                if (IsConnectionValid(connection))
                {
                    _activeConnections.TryAdd(connection.Name, connection);
                    ConnectionAcquiredCallback?.Invoke(connection);
                    Logger.Debug($"Acquired existing connection from pool: {connection.Name}");
                    return connection;
                }
                else
                {
                    // 连接无效，销毁它
                    DestroyConnection(connection);
                }
            }
            
            // 如果没有可用连接或连接无效，则创建新连接
            // 但要确保不超过最大池大小
            if (TotalConnectionCount < _maxPoolSize)
            {
                connection = CreateConnection();
                if (connection != null)
                {
                    _activeConnections.TryAdd(connection.Name, connection);
                    ConnectionCreatedCallback?.Invoke(connection);
                    ConnectionAcquiredCallback?.Invoke(connection);
                    Logger.Debug($"Created new connection for pool: {connection.Name}");
                    return connection;
                }
            }
            
            Logger.Warning("Connection pool exhausted, returning null");
            return null;
        }

        /// <summary>
        /// 归还连接到池中
        /// </summary>
        /// <param name="connection">要归还的连接</param>
        public void ReleaseConnection(TcpConnection connection)
        {
            if (_disposed || connection == null)
                return;

            // 从活动连接中移除
            _activeConnections.TryRemove(connection.Name, out _);
            
            // 检查连接是否有效
            if (IsConnectionValid(connection) && TotalConnectionCount < _maxPoolSize)
            {
                // 连接有效且池未满，归还到可用连接队列
                _availableConnections.Enqueue(connection);
                ConnectionReleasedCallback?.Invoke(connection);
                Logger.Debug($"Released connection to pool: {connection.Name}");
            }
            else
            {
                // 连接无效或池已满，销毁连接
                DestroyConnection(connection);
            }
        }

        /// <summary>
        /// 检查连接是否有效
        /// </summary>
        /// <param name="connection">连接</param>
        /// <returns>是否有效</returns>
        private bool IsConnectionValid(TcpConnection connection)
        {
            try
            {
                return connection != null && 
                       connection.State == TcpConnectionState.Connected &&
                       connection.Loop != null;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 销毁连接
        /// </summary>
        /// <param name="connection">要销毁的连接</param>
        private void DestroyConnection(TcpConnection connection)
        {
            try
            {
                connection?.Dispose();
                ConnectionDestroyedCallback?.Invoke(connection);
                Logger.Debug($"Destroyed connection: {connection?.Name ?? "null"}");
            }
            catch (Exception ex)
            {
                Logger.Error($"Error destroying connection: {ex.Message}", ex);
            }
        }

        /// <summary>
        /// 连接状态变化回调
        /// </summary>
        /// <param name="connection">连接</param>
        private void OnConnectionStateChanged(TcpConnection connection)
        {
            if (connection?.State == TcpConnectionState.Disconnected)
            {
                // 连接断开，从活动连接中移除
                _activeConnections.TryRemove(connection.Name, out _);
                // 销毁连接
                DestroyConnection(connection);
                
                // 如果当前连接数小于最小池大小，创建新连接补充
                if (TotalConnectionCount < _minPoolSize)
                {
                    var newConnection = CreateConnection();
                    if (newConnection != null)
                    {
                        _availableConnections.Enqueue(newConnection);
                        ConnectionCreatedCallback?.Invoke(newConnection);
                    }
                }
            }
        }

        /// <summary>
        /// 连接关闭回调
        /// </summary>
        /// <param name="connection">连接</param>
        private void OnConnectionClosed(TcpConnection connection)
        {
            // 从活动连接中移除
            _activeConnections.TryRemove(connection.Name, out _);
            // 销毁连接
            DestroyConnection(connection);
        }

        /// <summary>
        /// 总连接数
        /// </summary>
        private int TotalConnectionCount => _availableConnections.Count + _activeConnections.Count;

        /// <summary>
        /// 可用连接数
        /// </summary>
        public int AvailableConnectionCount => _availableConnections.Count;

        /// <summary>
        /// 活动连接数
        /// </summary>
        public int ActiveConnectionCount => _activeConnections.Count;

        /// <summary>
        /// 清理连接池
        /// </summary>
        public void Clear()
        {
            // 销毁所有可用连接
            while (_availableConnections.TryDequeue(out var connection))
            {
                DestroyConnection(connection);
            }
            
            // 销毁所有活动连接
            foreach (var connection in _activeConnections.Values)
            {
                DestroyConnection(connection);
            }
            
            _activeConnections.Clear();
        }

        public void Dispose()
        {
            if (!_disposed)
            {
                _disposed = true;
                Clear();
            }
        }
    }
}